﻿using Ionic.Zip;
using Pdf2epub.BusinessLogic;
using SharpEpub;
using SharpEpub.XmlBuilder;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Xml;
using XmlElement = SharpEpub.XmlBuilder.XmlElement;

namespace Pdf2epub.Epub
{
    public class EpubTableOfContents : AbstractFile
    {
        private readonly TocOptions m_TocOption = TocOptions.ByFilename;

        public EpubTableOfContents(EpubStructure structure, ZipFile file, TocOptions option, string bookId)
            : base(structure, file)
        {
            bookGuid = bookId;
            m_TocOption = option;
        }

        public EpubTableOfContents(EpubStructure structure, ZipFile file, TocOptions option)
            : base(structure, file)
        {
            m_TocOption = option;
        }

        public string BookTitle { get; set; }

        public string HtmlSourceFolder { get; set; }

        #region Overrides of AbstractFile

        protected override void Build()
        {
            xmlDocument = new XmlDocument();
            XmlBuilder document = xmlDocument.CreateXmlBuilder("ncx", new Dictionary<string, string>
			                                                          	{
			                                                          		{"xmlns", Resources.NcxNs},
			                                                          		{"version", Resources.NcxVersion}
			                                                          	});
            document.AppendElement(BuildHeadSection());
            document.AppendElement(BuildDocTitleSection());
            document.AppendElement(BuildNavMapSection());
            xmlDocument = document.GetDocument();
        }

        #endregion Overrides of AbstractFile

        private XmlElement BuildDocTitleSection()
        {
            XmlElement docTitleSection = xmlDocument.CreateXmlElement("docTitle");
            docTitleSection.AppendTextElement("text", BookTitle);
            return docTitleSection;
        }

        private XmlElement BuildHeadSection()
        {
            XmlElement headSection = xmlDocument.CreateXmlElement("head");
            var items = new List<Dictionary<string, string>>
			                                        	{
			                                        		new Dictionary<string, string>{ {"name", "dtb:depth"}, {"content", "1"}},
															new Dictionary<string, string>{ {"name", "dtb:totalPageCount"}, {"content", "1"}},
															new Dictionary<string, string>{ {"name", "dtb:uid"}, {"content", GetBookId}},
															new Dictionary<string, string>{ {"name", "dtb:maxPageNumber"}, {"content", "0"}}
			                                        	};
            foreach (var valuePair in items)
            {
                headSection.AppendElement("meta", valuePair);
            }
            return headSection;
        }

        private XmlElement BuildNavMapSection()
        {
            XmlElement navMapSection = xmlDocument.CreateXmlElement("navMap");

            int id = 0;

            foreach (ZipEntry entry in file.GetContentFiles(structure.Directories.ContentFolder))
            {
                id++;
                string mainChapterHref = string.Format("OPS/{0}", Path.GetFileName(entry.FileName));

                XmlElement navPointParent = navMapSection;
                string title = GetChapterTitle(entry);

                var navPointMainChapter = CreateNavPoint(id, navPointParent, title, mainChapterHref);

                string filename = Path.GetFileName(entry.FileName);
                if (filename == null)
                    continue;

                string fullSourceFilePath = Path.Combine(HtmlSourceFolder, filename);
                if (File.Exists(fullSourceFilePath))
                {
                    IEnumerable<SubChapter> foundSubChapters = ChapterHelpers.FindChapters(fullSourceFilePath, 2, 2);
                    foreach (var subChapter in foundSubChapters)
                    {
                        id++;
                        string subChapterHref = string.Format("{0}#{1}", mainChapterHref, subChapter.Href);
                        CreateNavPoint(id, navPointMainChapter, subChapter.Title, subChapterHref);
                    }
                }
            }
            return navMapSection;
        }

        private XmlElement CreateNavPoint(int id, XmlElement navPointParent, string title, string href)
        {
            Dictionary<string, string> attributes = new Dictionary<string, string>();
            attributes["playOrder"] = id.ToString(CultureInfo.InvariantCulture);
            attributes["id"] = "id" + id;

            XmlElement navPointElement = xmlDocument.CreateXmlElement("navPoint", attributes);
            navPointParent.AppendElement(navPointElement);

            XmlElement navLabelElement = xmlDocument.CreateXmlElement("navLabel");
            navPointElement.AppendElement(navLabelElement);
            navLabelElement.AppendTextElement("text", title);

            navPointElement.AppendElement("content", new KeyValuePair<string, string>("src", href));

            return navPointElement;
        }

        private string GetChapterTitle(ZipEntry entry)
        {
            return ((m_TocOption == TocOptions.ByTitleTag) || (m_TocOption == TocOptions.ByFirstH1Header)) ? entry.Comment : Path.GetFileNameWithoutExtension(entry.FileName);
        }
    }
}